package runc

import (
	"day3-mount-overlayfs-system/common"
	"day3-mount-overlayfs-system/image"
	"fmt"
	"golang.org/x/sys/unix"
	"log"
	"math/rand"
	"os"
	"path/filepath"
	"strings"
)

func createContainerID() string {
	randBytes := make([]byte, 6)
	rand.Read(randBytes) //always return nil
	id := fmt.Sprintf("%02x%02x%02x%02x%02x%02x",
		randBytes[0], randBytes[1], randBytes[2],
		randBytes[3], randBytes[4], randBytes[5])
	return id
}

func getContainerFsHome(containerID string) string {
	return filepath.Join(common.GetGockerContainerPath(), containerID, "fs")
}

func createContainerDirectories(containerID string) error {
	var (
		err error
	)

	//1.在指定的容器目录下构造/fs /fs/mnt /fs/upperdir /fs/workdir
	containerPath := common.GetGockerContainerPath() + containerID
	fsPaths := []string{containerPath + "/fs", containerPath + "/fs/mnt", containerPath + "/fs/upperdir", containerPath + "/fs/workdir"}

	//2.判断目录是否存在,不存在则创建
	for _, path := range fsPaths {

		_, err = os.Stat(path)
		if err != nil && os.IsNotExist(err) {
			//创建目录
			err := os.MkdirAll(path, 0644)
			if err != nil {
				log.Println("createContainerDirectories Mkdir failed!")
				return err
			}
		}
	}

	return err
}

//mountOverlayFileSystem 挂载为overlayfs文件系统
func mountOverlayFileSystem(containerID string, imageShaHex string) {
	var (
		err        error
		layers     []string
		srcLayers  []string
		contFSHome string
	)

	//1.从manifest文件中解析出layers信息
	manifestPath := image.GetManifestPathForImage(imageShaHex)
	layers, err = image.ParseLayersFromManifest(manifestPath)
	if err != nil {
		log.Println("ParseLayersFromManifest failed")
		return
	}

	//2.拼接layer全路径
	for _, layer := range layers {
		layerHash := layer[:12]
		path := image.GetLayerFsPathForImage(imageShaHex, layerHash)
		srcLayers = append(srcLayers, path)
	}

	//3.拼接挂载点语句
	contFSHome = getContainerFsHome(containerID)

	//4.调用unix.Mount进行挂载
	/*
		lowerdir=/var/lib/gocker/image/c059bfaa849c/47d7af55c64c/fs,
		upperdir=/var/run/gocker/containers/52fdfc072182/fs/upperdir,
		workdir=/var/run/gocker/containers/52fdfc072182/fs/workdir
	*/
	lowerdir := "lowerdir=" + strings.Join(srcLayers, ":")
	upperdir := "upperdir=" + contFSHome + "/upperdir"
	workdir := "workdir=" + contFSHome + "/workdir"
	mntOptions := lowerdir + "," + upperdir + "," + workdir //加逗号拼接
	log.Println("mntOptionsNew:", mntOptions)

	if err := unix.Mount("none", contFSHome+"/mnt", "overlay", 0, mntOptions); err != nil {
		log.Fatalf("Mount failed: %v\n", err)
	}
}

//InitContainer 容器初始化
func InitContainer(src string) {
	var (
		err          error
		imageHexHash string
	)

	//1.生成容器唯一id(小算法)
	containerID := createContainerID()

	//2.下载镜像
	imageHexHash, err = image.DownloadImageIfNessary(src)
	if err != nil {
		return
	}

	//3.创建容器目录
	err = createContainerDirectories(containerID)
	if err != nil {
		return
	}

	//4.挂载为overlayfs文件系统
	mountOverlayFileSystem(containerID, imageHexHash)

	//TODO: 5.开始运行容器实例
}
